#include <aknutils.h>
#include <akndef.h>
#include "ListBox.h"

CListBox* CListBox::NewL(const TRect& aRect, const CCoeControl* aParent)
	{
	CListBox* self = CListBox::NewLC(aRect, aParent);
	CleanupStack::Pop(self);
	return self;
	}

CListBox* CListBox::NewLC(const TRect& aRect, const CCoeControl* aParent)
	{
	CListBox* self = new(ELeave) CListBox();
	CleanupStack::PushL(self);
	self->ConstructL(aRect, aParent);
	return self;
	}

CListBox::~CListBox()
	{
	Components().ResetAndDestroy();
	delete iScrollBarFrame;
	iScrollBarFrame = NULL;
	iIconList.ResetAndDestroy();
	delete iSelItemBgBitmap;
	iSelItemBgBitmap = NULL;
	iLinePoint.Close();
	delete iNoData;
	iNoData = NULL;
	delete iCaption;
	iCaption = NULL;
	}

CListBox::CListBox()
	{
	iControlType = EList;
	iSelItemBgBitmap = NULL;
	iScrollBarFrame = NULL;
	iFocusControl = NULL;
	iMaxControlIndex = 0;
	iDrawLine = ETrue;
	iNoData = NULL;
	iCaption = NULL;
	}

void CListBox::ConstructL(const TRect& aRect, const CCoeControl* aParent)
	{
    if(aParent == NULL)
        {
        CreateWindowL();
        }
    else
        {
        SetContainerWindowL(*aParent);
        }
    // Initialize component array
    InitComponentArrayL();

    // Creating Scroll Bars
    iScrollBarFrame = new ( ELeave ) CEikScrollBarFrame( this, NULL );
    iScrollBarFrame->CreateDoubleSpanScrollBarsL( ETrue, EFalse );
    iScrollBarFrame->SetTypeOfVScrollBar( CEikScrollBarFrame::EDoubleSpan );
    iScrollBarFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff,
    		CEikScrollBarFrame::EOff );
    SetRect(aRect);
    ActivateL();
	}

TKeyResponse CListBox::OfferKeyEventL(
		const TKeyEvent& aKeyEvent, TEventCode aType )
	{
	if ( iFocusControl != NULL
		&& iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
		{
		if (iControlEventObserver)
			iControlEventObserver->HandleControlEventL(iFocusControl,EItemClick);
		return EKeyWasConsumed;
		}
	// Move focus
	TKeyResponse res = EKeyWasNotConsumed;
    switch ( aKeyEvent.iCode )
        {
        case EKeyUpArrow:
            {
            if (MoveFocusUpL())
            	res =  EKeyWasConsumed;
            break;
            }
        case EKeyDownArrow:
            {
            if (MoveFocusDownL())
            	res =  EKeyWasConsumed;
            break;
            }
        default:
            {
            res =  EKeyWasNotConsumed;
            break;
            }
        }
    DrawNow(); // Draw components again
    return res;
	}

void CListBox::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl->Rect().Contains(aPointerEvent.iPosition))
        	{
        	if (ctrl->IsFocused())
        		ctrl->HandlePointerEventL(aPointerEvent);
        	else
        		{
        		iFocusControl->SetFocus(EFalse);
        		iFocusControl = ctrl;
        		iFocusControl->SetFocus(ETrue);
        		iFocusedIndex = Components().Id(*iFocusControl);
        		}
        	break;
        	}
        cursor.Next();
        }
    DrawNow();
	}

void CListBox::AddListItemL(CListItem* aControl)
	{
	// NOTE: Transfer ownership of CCoeControl to CContainerControl
    // Add control into container control
    Components().AppendLC(aControl,iMaxControlIndex++);
    CleanupStack::Pop(aControl);

    // Focus first component
    if (Components().Count()== 1)
        {
        aControl->SetFocus(ETrue);
        aControl->SetPosition(Position());
        iFocusControl = aControl;
        iFocusedIndex = 0;
        }
	}

void CListBox::RemoveItem(CListItem* aControl)
	{
	Components().Remove(aControl);
	delete aControl;
	aControl = NULL;
	}

void CListBox::RemoveAllItems()
	{
	CCoeControlArray::TCursor cursor = Components().Begin();
	CCoeControl* ctrl = NULL;
	while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
		{
		Components().Remove(ctrl);
		delete ctrl;
		ctrl = NULL;
		}
	}

TInt CListBox::Count()
{
    return Components().Count();
}

void CListBox::Draw(const TRect& aRect) const
	{
	CWindowGc& gc = SystemGc();
	gc.SetClippingRect(aRect);
	gc.Clear(aRect);
	CBaseControl::Draw(gc, aRect);
	if (iDrawLine)
		{
		gc.SetPenStyle(CGraphicsContext::ESolidPen);
		gc.SetPenColor(KRgbGray);
		for(TInt i = 0; i < iLinePoint.Count(); i++)
			{
			gc.DrawLine(TPoint(iLinePoint[i].iX,iLinePoint[i].iY - 1),
					TPoint(aRect.iBr.iX,iLinePoint[i].iY -1));
			}
		}
	if (Components().Count() <= 0 && iNoData)
	{
	    const CFont* fontUsed = CEikonEnv::Static()->NormalFont();
	    gc.UseFont(fontUsed);
        gc.SetPenColor(TRgb(204, 85, 1));
        TInt baseline = aRect.Height() / 2 + fontUsed->AscentInPixels() / 2;
        gc.DrawText(*iNoData, aRect, baseline, CGraphicsContext::ECenter, 0);
        gc.DiscardFont();//dicard the font
        
        fontUsed = ApacPlain16();
        gc.UseFont(fontUsed);
        if (iCaption)
        {
            TRect rc = aRect;
            rc.iTl = TPoint(aRect.iTl.iX ,aRect.Height() / 2 + fontUsed->HeightInPixels() * 4);
            rc.SetHeight(fontUsed->HeightInPixels() * 2);
            baseline = rc.Height() / 2 + fontUsed->AscentInPixels() / 2;
            gc.DrawText(*iCaption, rc, baseline, CGraphicsContext::ECenter, 0);
        }
	    gc.DiscardFont();//dicard the font
	}
	gc.CancelClippingRect();
	}

void CListBox::SizeChanged(const TRect& aRect)
	{
	SetRect(aRect);
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        static_cast< CBaseControl* >(ctrl)->SizeChanged(Rect());
        cursor.Next();
        }
    TInt offset(0);
    if (iFocusControl)
    	{
    	if (IsInRect(iFocusControl))
    		{
			if (iFocusControl->Rect().iTl.iY < Rect().iTl.iY)
				offset = Rect().iTl.iY - iFocusControl->Rect().iTl.iY;
			if (iFocusControl->Rect().iBr.iY > Rect().iBr.iY)
				offset = Rect().iBr.iY - iFocusControl->Rect().iBr.iY;
    		}
    	else
    		{
    		offset = iFocusControl->Rect().iTl.iY - Rect().iTl.iY;
    		}
		}
    if (offset != 0)
    	UpdateControls(offset);
	}


void CListBox::FocusChanged(TDrawNow /*aDrawNow*/)
	{
	if (iFocusControl)
		{
		if (IsFocused())
			{
			iFocusControl->SetFocus(ETrue);
			}
		else
			{
			iFocusControl->SetFocus(EFalse);
			}
		}
	}

TBool CListBox::MoveFocusUpL()
	{
	CCoeControlArray::TCursor cursor = Components().Begin();
	CCoeControl* ctrl= NULL;
	CCoeControl* prevCtrl= NULL;
	while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
		{
		if (ctrl->IsFocused())
			{
			if (prevCtrl)
				{
				// Set focus to previous control
				ctrl->SetFocus(EFalse);
				prevCtrl->SetFocus(ETrue);
				iFocusControl = prevCtrl;
				iFocusedIndex--;

				// Focus is over the view?
				if (iFocusedIndex >= 0 && prevCtrl->Rect().iTl.iY < Rect().iTl.iY)
					{
					UpdateControls(Rect().iTl.iY - prevCtrl->Rect().iTl.iY);
					return ETrue;
					}
				break;
				}
			else
				{
				return EFalse; // First control is already focused
				}
			}
		prevCtrl = ctrl;
		cursor.Next();
		}
	UpdateScrollBarFrameL();
	return ETrue;
	}

TBool CListBox::MoveFocusDownL()
	{
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    CCoeControl* nextCtrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl && ctrl->IsFocused())
            {
            cursor.Next();
            nextCtrl = cursor.Control<CCoeControl>();
            if (nextCtrl)
                {
                // Set focus to next control
                ctrl->SetFocus(EFalse);
                nextCtrl->SetFocus(ETrue);
                iFocusControl = nextCtrl;
                iFocusedIndex++;

                // Focus is over the view?
                if (nextCtrl->Rect().iBr.iY > Rect().iBr.iY)
                    {
                    UpdateControls(Rect().iBr.iY - nextCtrl->Rect().iBr.iY);
                    return ETrue;
                    }
                break;
                }
            else
                {
                return EFalse; // Last control is already focused
                }
            }
        cursor.Next();
        }
    UpdateScrollBarFrameL();
    return ETrue;
	}

void CListBox::UpdateControls(TInt aOffset)
	{
	if (Components().Count() <= 0)
		return ;
	TPoint position;
    // Goes through all components of this container control
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = cursor.Control<CCoeControl>();
    if (ctrl)
    	position = ctrl->Position();
    position.iY += aOffset;
    iLinePoint.Reset();
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        // Set position
        ctrl->SetPosition(position);
        position.iY += ctrl->Rect().Height() + 1;
        if ( IsInRect(ctrl) )
            {
            ctrl->MakeVisible(ETrue);
            iLinePoint.Append(position);
            }
        else
            {
            ctrl->MakeVisible(EFalse);
            }
        cursor.Next();
        }
    UpdateScrollBarFrameL();
	}

void CListBox::UpdateScrollBarFrameL()
	{
	if (Components().Count() <= 0)
		return ;
	TInt totalHeight = 0; // Height of the controls
    TInt height = 0; // This view height
    // Calculate components height
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        totalHeight += ctrl->Size().iHeight;
        cursor.Next();
        }

    // This view height
    height = Rect().Height();

    // Set teh scrollbar visible if fields do not fit the screen
    if( totalHeight > height &&
         iScrollBarFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOff)
        {
        iScrollBarFrame->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, // horizontal
                CEikScrollBarFrame::EOn); // vertical
        }
    // Hide the scrollbar if fields fit the screen
    else if ( totalHeight <= height &&
              iScrollBarFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn)
        {
        iScrollBarFrame->SetScrollBarVisibilityL(
                CEikScrollBarFrame::EOff, // horizontal
                CEikScrollBarFrame::EOff); // vertical
        }
    if (totalHeight <= height)
    	{
        CCoeControlArray::TCursor cursor = Components().Begin();
        CCoeControl* ctrl = NULL;
        while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
            {
            ((CBaseControl*)ctrl)->SizeChanged(Rect());
            cursor.Next();
            }
    	}
    // Update scroll bar position
    iVDsSbarModel.SetScrollSpan(Components().Count());
    iVDsSbarModel.SetWindowSize(1);
    iVDsSbarModel.SetFocusPosition(iFocusedIndex);
    TEikScrollBarFrameLayout layout;
    layout.iTilingMode = TEikScrollBarFrameLayout::EInclusiveRectConstant;
    TRect rect = Rect();
    iScrollBarFrame->TileL(&iHDsSbarModel,&iVDsSbarModel,rect,rect,layout);
    iScrollBarFrame->SetVFocusPosToThumbPos(iVDsSbarModel.FocusPosition());
	}

TBool CListBox::IsInRect(CCoeControl* aCtrl)
	{
	if (aCtrl && (Rect().Contains(aCtrl->Position()) || Rect().iTl.iY < aCtrl->Rect().iBr.iY))
		return ETrue;
	else
		return EFalse;
	}

void CListBox::AddIconL(CFbsBitmap* aBitmap)
	{
	iIconList.AppendL(aBitmap);
	}

void CListBox::AddBitmap(const TDesC& aFileName,TInt aBitmapId)
	{
    CFbsBitmap* bitmap = AknIconUtils::CreateIconL(aFileName,aBitmapId);
    if (bitmap)
        AddIconL(bitmap);
	}

void CListBox::AddBitmap(CFbsBitmap* aBitmap)
	{
	if (aBitmap)
		AddIconL(aBitmap);
	}

CFbsBitmap* CListBox::GetBitmap(TInt aIndex)
	{
	if (aIndex >= 0 && aIndex < iIconList.Count())
		return iIconList[aIndex];
	return NULL;
	}

void CListBox::SetCurrentItemIndex(TInt aIndex)
	{
	if (aIndex >= 0 && aIndex < Components().Count())
		{
		iFocusControl->SetFocus(EFalse);
		TCoeControlWithId a = Components().At(aIndex);
		iFocusControl = a.iControl;
		iFocusControl->SetFocus(ETrue);
		iFocusedIndex = aIndex;
		}
	}

TInt CListBox::CurrentItemIndex()
	{
	return iFocusedIndex;
	}

CCoeControl* CListBox::FocusedItem()
	{
	return iFocusControl;
	}

CCoeControl* CListBox::GetItem(TInt aIndex)
	{
	if (aIndex >= Components().Count())
		return NULL;
	TCoeControlWithId a = Components().At(aIndex);
	return a.iControl;
	}

void CListBox::SetDrawLine(TBool aDrawLine)
	{
	iDrawLine = aDrawLine;
	}

void CListBox::SetSelItemBackGroundBitmapL(CFbsBitmap* aBitmap)
    {
    delete iSelItemBgBitmap;
    iSelItemBgBitmap = aBitmap;
    }

CFbsBitmap* CListBox::SelItemBackGroundBitmap() const
    {
    return iSelItemBgBitmap;
    }

void CListBox::SetNoDataL(const TDesC& aText)
{
    delete iNoData;
    iNoData = aText.AllocL();
}

void CListBox::SetCaptionL(const TDesC& aCaption)
{
    delete iCaption;
    iCaption = aCaption.AllocL();
}
